/*
 * Copyright (c) China Telecom Cloud Technology Co., Ltd. 2024-2025. All rights reserved.
 */
#include "../include/PosixStrategy.h"
#include "Common.h"
#include "KvcBaseDefine.h"
#include <algorithm>
#include <cstring>
#include <filesystem>
#include <sys/xattr.h>

#define VERIFY_HASH_ID_XATTR_NAME "user.verify_hash_id"


int32_t PosixStartegy::get(const std::string &objId, 
                        const Segment  &segment,
                        const uint64_t srcOffset, 
                        const uint64_t dstOffset,
                        const uint64_t length
                    ) noexcept {

    auto path  = getFileFullPath(objId);  // 根据objId获取完整的KV Cache文件路径
    auto start = getCurrentTimestampUs(); // 记录函数开始时间

    int32_t fd = ::open(path.c_str(), O_RDONLY | O_DIRECT);
    if (fd < 0) {
        LOG_WARN_FMT("open path failed fd={}, path:{}", fd, path.c_str());
        return KVC_ERR_FILEOP_FAIL;
    }
    auto open_end = getCurrentTimestampUs();
    LOG_DEBUG_FMT("open file cost time : {} us", open_end - start);


    // TODO(yangxianpku: 2025.08.21): 如果segment.getVerifyHashId()全0不用把从文件
    // 读取到的verifyHashId数据赋值给如果segment么？
    if (std::any_of(segment.getVerifyHashId(),
                    segment.getVerifyHashId() + VERIFY_HASH_LENGTH,
                    [](char c) { return c != 0; })) {
        // 有非零表示开启，需要从文件中读取该值
        char verifyHashId[VERIFY_HASH_LENGTH];

        // 通过文件读取的VERIFY_HASH_ID_XATTR_NAME属性值存入verifyHashId中
        ssize_t bytes_read = getxattr(path.c_str(), 
                                    VERIFY_HASH_ID_XATTR_NAME,
                                    verifyHashId, 
                                    VERIFY_HASH_LENGTH
                                );
        
        // 文件读取的备份哈希与segment附带的冲突，验证不一致
        if (bytes_read != -1 && memcmp(segment.getVerifyHashId(), 
                                    verifyHashId,
                                    VERIFY_HASH_LENGTH) != 0) {
            LOG_WARN_FMT("secondary hash conflict! fd={}, path:{}", fd,
                         path.c_str());
            return KVC_ERR_FILEOP_FAIL;
        }
    }

    // 读取数据到segment.getMemAddr() + srcOffset
    
    /**
     *! @brief 从文件读取KV Cache数据到segment中(线程安全)
     * 
     * @param 文件描述符
     * @param 读取文件数据存入的地址指针
     * @param 读取数据量大小
     * @param 从文件指定偏移处读取
     * 
     * @return 返回读取到的字节数，-1表示读取失败
     */
    // pread (int __fd, void *__buf, size_t __nbytes, __off_t __offset)
    auto bytes =
        ::pread(fd, segment.getMemAddr() + srcOffset, length, dstOffset);
    close(fd);

    if (bytes != length) {
        LOG_ERROR_FMT("read file failed bytes({}) != length({})", (long)bytes,
                      length);
        return KVC_ERR_FILEOP_FAIL;
    }

    auto read_end = getCurrentTimestampUs();
    LOG_DEBUG_FMT("read file cost time : {} us", read_end - open_end);
    LOG_DEBUG_FMT("cost time : {}", read_end - start);

    return KVC_OK;
}



int32_t PosixStartegy::put(const std::string &objId, 
                        const Segment &segment,
                        const uint64_t srcOffset, 
                        const uint64_t dstOffset,
                        const uint64_t length
                    ) noexcept {
    auto start = getCurrentTimestampUs(); // 记录函数开始时间

    auto path  = getFileFullPath(objId);
    int32_t fd = createFileWithPath(path, O_WRONLY | O_CREAT | O_DIRECT,
                                    USER_READ_WRITE);
    if (fd < 0) {
        LOG_WARN_FMT("open path failed, errno={}", errno);
        return KVC_ERR_FILEOP_FAIL;
    }
    auto open_end = getCurrentTimestampUs();
    LOG_DEBUG_FMT("open file cost time : {} us", open_end - start);

    auto bytes =
        ::pwrite(fd, segment.getMemAddr() + srcOffset, length, dstOffset);
    close(fd);
    if (bytes != length) {
        LOG_ERROR_FMT("write file failed bytes({}) != length({})", (long)bytes,
                      length);
        return KVC_ERR_FILEOP_FAIL;
    }

    if (std::any_of(segment.getVerifyHashId(),
                    segment.getVerifyHashId() + VERIFY_HASH_LENGTH,
                    [](char c) { return c != 0; })) {
        // 设置该文件的备用哈希属性
        int result = setxattr(path.c_str(), 
                            VERIFY_HASH_ID_XATTR_NAME,
                            segment.getVerifyHashId(), 
                            VERIFY_HASH_LENGTH, 
                            0
                        );
        if (result == -1) {
            LOG_WARN_FMT("secondary hash save failed! fd={}, "
                        "path:{}", fd, path.c_str());
        }
    }

    auto end = getCurrentTimestampUs(); // 记录函数结束时间
    LOG_DEBUG_FMT("put file cost time : {} us", end - open_end);
    LOG_DEBUG_FMT("cost time : {}", end - start);
    return KVC_OK;
}




int32_t PosixStartegy::remove(const std::string &objId) noexcept {
    auto path = getFileFullPath(objId);
    auto ret  = ::remove(path.c_str()); 
    
    if (ret != 0) {
        LOG_ERROR_FMT("remove file failed");
        return KVC_ERR_FILEOP_FAIL;
    }
    return KVC_OK;
}



bool PosixStartegy::isExist(const std::string &objId) noexcept {
    auto path = getFileFullPath(objId);
    struct stat info;
    return (::stat(path.c_str(), &info) == 0);
}